package httpclient

import (
	"encoding/base64"
	"io"
	"net/http"
	"net/url"
	"strings"
)

// AuthMethod 定义认证方法接口
type AuthMethod interface {
	Apply(req *http.Request)
}

// BasicAuth 实现 Basic 认证
type BasicAuth struct {
	Username string
	Password string
}

// Apply 实现 AuthMethod 接口
func (a BasicAuth) Apply(req *http.Request) {
	auth := a.Username + ":" + a.Password
	req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
}

// BearerToken 实现 Bearer Token 认证
type BearerToken struct {
	Token string
}

// Apply 实现 AuthMethod 接口
func (b BearerToken) Apply(req *http.Request) {
	req.Header.Set("Authorization", "Bearer "+b.Token)
}

// APIKeyAuth 实现 API Key 认证
type APIKeyAuth struct {
	Key   string
	Place string // "header" 或 "query"
	Name  string // Header 名称或 Query 参数名
}

// Apply 实现 AuthMethod 接口
func (a APIKeyAuth) Apply(req *http.Request) {
	switch a.Place {
	case "header":
		req.Header.Set(a.Name, a.Key)
	case "query":
		query := req.URL.Query()
		query.Add(a.Name, a.Key)
		req.URL.RawQuery = query.Encode()
	}
}

// RequestOptions 封装请求选项
type RequestOptions struct {
	Method     string
	Headers    map[string]string
	AuthMethod AuthMethod
	Query      url.Values
	Body       io.Reader
}

// Client 封装 HTTP 客户端和请求配置
type Client struct {
	httpClient *http.Client
	baseURL    string
}

// NewClient 创建一个新的 HTTP 客户端
func NewClient(baseURL string) *Client {
	return &Client{
		httpClient: &http.Client{},
		baseURL:    baseURL,
	}
}

// Fetch 发送 HTTP 请求
func (c *Client) Fetch(path string, options RequestOptions) (*http.Response, error) {
	// 构建完整 URL
	url := strings.TrimSuffix(c.baseURL, "/") + "/" + strings.TrimPrefix(path, "/")
	if len(options.Query) > 0 {
		url = strings.Join([]string{url, options.Query.Encode()}, "?")
	}

	// 创建请求
	req, err := http.NewRequest(options.Method, url, options.Body)
	if err != nil {
		return nil, err
	}

	// 设置请求头
	for key, value := range options.Headers {
		req.Header.Set(key, value)
	}

	// 设置认证
	if options.AuthMethod != nil {
		options.AuthMethod.Apply(req)
	}

	// 发送请求
	return c.httpClient.Do(req)
}
